package junior.db.dao.update;

import com.google.common.collect.Lists;
import junior.db.dao.base.MybatisHelper;
import junior.db.dao.ext.IBatchExtensible;
import junior.db.query.QueryHelper;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author wubo
 * @date 2024/8/29 17:32
 */
public class AbstractBatchInsertOption<O> extends AbstractInsertOption<O> implements IBatchExtensible {
    protected Object[] entities;
    protected List<Object[]> insertValues;
    private List<Map<String, Object>> exts;
    private List<String> extFields;
    
    public List<Object[]> getInsertValues() {
        return insertValues;
    }
    
    @Override
    public void beforeExecuteNode() {
        initFields();
        initValues();
    }
    
    @Override
    public IBatchExtensible doEntityExt(List<String> fields) {
        this.extFields = fields;
        return this;
    }
    
    @Override
    public IBatchExtensible doExt(List<Map<String, Object>> exts, List<String> fields) {
        this.exts = exts;
        this.extFields = fields;
        return this;
    }
    
    protected void initFields() {
        String[] ignoreFields = excludeFields;
        if (ignoreFields == null) {
            ignoreFields = new String[0];
        }
        if (insertFields == null) {
            insertFields = QueryHelper.getDBFieldNames(entityClass, "", ignoreFields);
        } else if (ignoreFields.length > 0 || extFields != null) {
            Set<String> excludeFieldSet = new HashSet<>(Arrays.asList(ignoreFields));
            Set<String> fields = Arrays.stream(insertFields).filter(field -> !excludeFieldSet.contains(field)).collect(Collectors.toSet());
            if (extFields != null) {
                fields.addAll(extFields);
            }
            insertFields = fields.toArray(new String[0]);
        }
    }
    
    protected void initValues() {
        insertValues = Lists.newArrayListWithCapacity(entities.length);
        for (Object entity : entities) {
            Object[] entityValues = new Object[insertFields.length];
            for (int i=0; i<insertFields.length; i++) {
                String field = insertFields[i];
                entityValues[i] = getValue(entity, field, i);
            }
            insertValues.add(entityValues);
        }
    }
    
    protected Object getValue(Object entity, String field, int entityIndex) {
        if (exts != null && exts.get(entityIndex) != null && exts.get(entityIndex).containsKey(field)) {
            return exts.get(entityIndex).get(field);
        }
        String expression = insertFieldExpressionMap == null ? null : insertFieldExpressionMap.get(field);
        if (expression != null) {
            return MybatisHelper.sqlToSqlValue(namespace, entityClass, expression, f -> MybatisHelper.getFieldValue(entity, f));
        }
        return MybatisHelper.getFieldValue(entity, field);
    }
    
    void init(Class<?> entityClass, Object[] entities) {
        super.entityClass = entityClass;
        this.entities = entities;
        
        for (Object entity : entities) {
            UpdateOptionHelper.entityBeforeInsert(this, entity);
        }
        
        if (insertFields == null) {
            insertFields = QueryHelper.getDBFieldNames(entityClass, null);
        }
    }
}
